#include "stdafx.h"
#include "log/windowsconsolechannel.hpp"
#include "charset/string.hpp"
using namespace JHCPP::charset;

namespace JHCPP
{
	namespace log
	{
		//////////////////////////////////////////////////////////////////////////
		//CWindowsConsoleChannel
		//////////////////////////////////////////////////////////////////////////
		CWindowsConsoleChannel::CWindowsConsoleChannel() : m_isFile(false), m_hConsole(INVALID_HANDLE_VALUE)
		{
			m_hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);

			DWORD mode;	
			m_isFile = (::GetConsoleMode(m_hConsole, &mode) == 0);
		}

		CWindowsConsoleChannel::~CWindowsConsoleChannel()
		{
		}

		void CWindowsConsoleChannel::log(const CMessage& msg)
		{
			std::string text = msg.getText();
			text += "\r\n";

			DWORD written;
			::WriteFile(m_hConsole, text.data(), text.size(), &written, NULL);	
		}


		//////////////////////////////////////////////////////////////////////////
		//CWindowsColorConsoleChannel
		//////////////////////////////////////////////////////////////////////////
		CWindowsColorConsoleChannel::CWindowsColorConsoleChannel()
		: m_enableColors(true),
		m_isFile(false),
		m_hConsole(INVALID_HANDLE_VALUE)
		{
			m_hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);

			DWORD mode;	
			m_isFile = (::GetConsoleMode(m_hConsole, &mode) == 0);
			initColors();
		}

		CWindowsColorConsoleChannel::~CWindowsColorConsoleChannel()
		{
		}

		void CWindowsColorConsoleChannel::log(const CMessage& msg)
		{
			std::string text = msg.getText();
			text += "\r\n";

			if (m_enableColors && !m_isFile)
			{
				WORD attr = m_colors[0];
				attr &= 0xFFF0;
				attr |= m_colors[msg.getPriority()];
				::SetConsoleTextAttribute(m_hConsole, attr);
			}

			DWORD written;
			::WriteFile(m_hConsole, text.data(), text.size(), &written, NULL);	


			if (m_enableColors && !m_isFile)
			{
				::SetConsoleTextAttribute(m_hConsole, m_colors[0]);
			}
		}

		void CWindowsColorConsoleChannel::setProperty(const std::string& name, const std::string& value)
		{
			if (name == "enableColors")
			{
				m_enableColors = icompare(value, "true") == 0;
			}
			else if (name == "traceColor")
			{
				m_colors[CMessage::PRIO_TRACE] = parseColor(value);
			}
			else if (name == "debugColor")
			{
				m_colors[CMessage::PRIO_DEBUG] = parseColor(value);
			}
			else if (name == "informationColor")
			{
				m_colors[CMessage::PRIO_INFORMATION] = parseColor(value);
			}
			else if (name == "noticeColor")
			{
				m_colors[CMessage::PRIO_NOTICE] = parseColor(value);
			}
			else if (name == "warningColor")
			{
				m_colors[CMessage::PRIO_WARNING] = parseColor(value);
			}
			else if (name == "errorColor")
			{
				m_colors[CMessage::PRIO_ERROR] = parseColor(value);
			}
			else if (name == "criticalColor")
			{
				m_colors[CMessage::PRIO_CRITICAL] = parseColor(value);
			}
			else if (name == "fatalColor")
			{
				m_colors[CMessage::PRIO_FATAL] = parseColor(value);
			}
			else
			{
				CChannel::setProperty(name, value);
			}
		}

		std::string CWindowsColorConsoleChannel::getProperty(const std::string& name) const
		{
			if (name == "enableColors")
			{
				return m_enableColors ? "true" : "false";
			}
			else if (name == "traceColor")
			{
				return formatColor(m_colors[CMessage::PRIO_TRACE]);
			}
			else if (name == "debugColor")
			{
				return formatColor(m_colors[CMessage::PRIO_DEBUG]);
			}
			else if (name == "informationColor")
			{
				return formatColor(m_colors[CMessage::PRIO_INFORMATION]);
			}
			else if (name == "noticeColor")
			{
				return formatColor(m_colors[CMessage::PRIO_NOTICE]);
			}
			else if (name == "warningColor")
			{
				return formatColor(m_colors[CMessage::PRIO_WARNING]);
			}
			else if (name == "errorColor")
			{
				return formatColor(m_colors[CMessage::PRIO_ERROR]);
			}
			else if (name == "criticalColor")
			{
				return formatColor(m_colors[CMessage::PRIO_CRITICAL]);
			}
			else if (name == "fatalColor")
			{
				return formatColor(m_colors[CMessage::PRIO_FATAL]);
			}
			else
			{
				return CChannel::getProperty(name);
			}
		}

		WORD CWindowsColorConsoleChannel::parseColor(const std::string& color) const
		{
			if (icompare(color, "default") == 0)
				return m_colors[0];
			else if (icompare(color, "black") == 0)
				return CC_BLACK;
			else if (icompare(color, "red") == 0)
				return CC_RED;
			else if (icompare(color, "green") == 0)
				return CC_GREEN;
			else if (icompare(color, "brown") == 0)
				return CC_BROWN;
			else if (icompare(color, "blue") == 0)
				return CC_BLUE;
			else if (icompare(color, "magenta") == 0)
				return CC_MAGENTA;
			else if (icompare(color, "cyan") == 0)
				return CC_CYAN;
			else if (icompare(color, "gray") == 0)
				return CC_GRAY;
			else if (icompare(color, "darkGray") == 0)
				return CC_DARKGRAY;
			else if (icompare(color, "lightRed") == 0)
				return CC_LIGHTRED;
			else if (icompare(color, "lightGreen") == 0)
				return CC_LIGHTGREEN;
			else if (icompare(color, "yellow") == 0)
				return CC_YELLOW;
			else if (icompare(color, "lightBlue") == 0)
				return CC_LIGHTBLUE;
			else if (icompare(color, "lightMagenta") == 0)
				return CC_LIGHTMAGENTA;
			else if (icompare(color, "lightCyan") == 0)
				return CC_LIGHTCYAN;
			else if (icompare(color, "white") == 0)
				return CC_WHITE;
			else throw InvalidArgumentException("Invalid color value", color);
		}

		std::string CWindowsColorConsoleChannel::formatColor(WORD color) const
		{
			switch (color)
			{
			case CC_BLACK:        return "black";
			case CC_RED:          return "red";
			case CC_GREEN:        return "green";
			case CC_BROWN:        return "brown";
			case CC_BLUE:         return "blue";
			case CC_MAGENTA:      return "magenta";
			case CC_CYAN:         return "cyan";
			case CC_GRAY:         return "gray";
			case CC_DARKGRAY:     return "darkGray";
			case CC_LIGHTRED:     return "lightRed";
			case CC_LIGHTGREEN:   return "lightGreen";
			case CC_YELLOW:       return "yellow";
			case CC_LIGHTBLUE:    return "lightBlue";
			case CC_LIGHTMAGENTA: return "lightMagenta";
			case CC_LIGHTCYAN:    return "lightCyan";
			case CC_WHITE:        return "white";
			default:              return "invalid";
			}
		}

		void CWindowsColorConsoleChannel::initColors()
		{
			if (!m_isFile)
			{
				CONSOLE_SCREEN_BUFFER_INFO csbi;
				::GetConsoleScreenBufferInfo(m_hConsole, &csbi);
				m_colors[0] = csbi.wAttributes;
			}
			else
			{
				m_colors[0] = CC_WHITE;
			}
			m_colors[CMessage::PRIO_FATAL]       = CC_LIGHTRED;
			m_colors[CMessage::PRIO_CRITICAL]    = CC_LIGHTRED;
			m_colors[CMessage::PRIO_ERROR]       = CC_LIGHTRED;
			m_colors[CMessage::PRIO_WARNING]     = CC_YELLOW;
			m_colors[CMessage::PRIO_NOTICE]      = m_colors[0];
			m_colors[CMessage::PRIO_INFORMATION] = m_colors[0];
			m_colors[CMessage::PRIO_DEBUG]       = CC_GRAY;
			m_colors[CMessage::PRIO_TRACE]       = CC_GRAY;
		}

	}//end of namespace log
}//end of namespace JHCPP
